這一篇主要提到的都是關於非同步以及同步處理的方式,ES6 有提供 Promise
來處理同步非同步行為,後續也有 async await 讓非同步行為更容易處理。
Promise 其實是一個原生的構造函數,可以透過 new 來生成實例。它接受一個函式作為參數,這個參數會有 resolve 和 reject 兩個參數,分別代表成功和失敗。Promise
中總共有三種狀態,pending(等待、未完成)、resolve(成功)、reject(失敗)。Promise
的使用一般是先用 new
生成一個實例,賦給變數,之後藉由呼叫該變數直接調用,如下面的範例。我們可以在實例中去判斷 resolve 和 reject 時要執行什麼事情。調用 Promise
後可以用 then
來接續去取得 Promise
執行後回傳的結果。then
是 Promise
實例的一個方法,接受兩個回調函數作為參數(reject, resolve),執行完後會返回一個 promise 物件,因此可以用 then
再接下去,一直 then
, then
...。catch
是非同步異常時候會執行的事情,finally
則是無論成功失敗,都會執行的事情。
const promise = new Promise((resolve, reject) => {
if (true) {
resolve(1);//resolve 會返回一個值,這個返回的數值實際上掛在 promise 實例裡面
} else {
reject(2);
}
})
promise.then( //訪問 then,then 會返回一個新的 promise
//resolve 回調函數
value => {
console.log(value)//1,resolve 回調函數
// 成功要執行的事情
return 10
},
error => {
// 失敗要執行的事情
console.log(error)//2,reject 回調函數
return 5
}
).then(
value => {
console.log(value)//10
return 20
},
error => {
console.log(error)
return 5
}
).then(
value => {
console.log(value)//20
return 30
},
error => {
console.log(error)
return 5
}
).catch (error => {
//非同步異常
}).finally(() => {
//沒有參數
//無論失敗成功都會執行
});
這邊整理兩個一次執行多個 Promise
的方法,Promise.all
與 Promise.race
。Promise.all()
會同時執行所有 Promise
,並在全部完成後統一回傳陣列,這個陣列的內容也是 Promise
中 resolve 的內容,但如果當中有 reject 事件,整個 Promise
都會被視為失敗。Promise.race
可以傳入多個 Promise
事件,這個方法只會回傳第一個完成的事件。
const bikeRace = (name, time) => {
return new Promise((resolve, reject) => {
if(time > 0) {
setTimeout(() => {
let str = name + '花費' + (time / 1000) +'秒完成比賽';
resolve(str);
}, time)
} else {
let str = name + '於比賽中作弊~!!!!';
reject(str);
};
});
};
Promise.race([bikeRace('Leo', 12000), bikeRace('Jack', 9000), bikeRace('Lun', 13000), bikeRace('Willie', 30000)]).then((data) => {
// 只會回傳最快完成的 reslove 或 reject
console.log(data) // "Jack 花費 9 秒完成跑完 100 公尺"
}).catch((error) => {
console.log(error)
});
Promise.all([bikeRace('Leo', 12000), bikeRace('Jack', 9000), bikeRace('Lun', 13000), bikeRace('Willie', 30000)]).then((data) => {
// 回傳全部結果
console.log(data) //["Leo 花費 12 秒完成跑完 100 公尺", "Jack 花費 9 秒完成跑完 100 公尺", "Lun 花費 13 秒完成跑完 100 公尺", "Willie 花費 30 秒完成跑完 100 公尺"]
}).catch((error) => {
console.log(error)
});
Promise.all([bikeRace('Leo', 12000), bikeRace('Jack', 9000), bikeRace('Lun', 13000), bikeRace('Willie', 0)]).then((data) => {
// 回傳全部結果
console.log(data) //Willie跑步時閃到腰摔倒~!!!!
}).catch((error) => {
console.log(error)
});
ES8 引入了 async
、await
函數讓非同步處理更為方便,async
與 await
是建構於 Promise
之上的。Promise
中完成會透過 then
來回傳,在 await
則是會等待這段函式完成後再往下繼續執行。由於 await
如果遇到錯誤就會造成停止讓後方程式碼不執行,因此通常搭配 async
使用。async
的結構非常類似 Promise
,只不過他能夠將 await
包在裡面,被包在裡面的 await
就如同先前的結構一樣,會依序地執行。async
本身也是類似 Promise
,在正確執行的情況下 return 會傳回 resolved 的狀態,也可以使用 then
來接收正確的資料,並使用 catch
和 finally
來執行非同步失敗及最後要執行的事情
await
接非同步處理行為,通常是接 Promise
,並且會等到處理完畢回傳,才會繼續執行的程式碼。如下面的範例,await
後面接著 fetch
去發出 request,之後會返回一個 Promise
,Promise
會透過 then
做處理返回我們需要的資料,直到這些事情都執行完畢,才會執行後續的程式碼。如果沒有用 then
之類的方法,得到的會是 response,並不是真的數據,必須再使用如 .json()
之類的方法做處理。
async function getApi() {
try {
const res = await fetch('./post.json').then(res => res.json());
} catch(err) {
//異步異常
console.log(err)
} finally {
console.log('done')
}
};
//調用
getApi();
async
函數是返回一個 Promise
物件,async
如果有返回值,返回值會成為 then 方法回調的函數
async function getApi() {
try {
return await fetch('./post.json');
} catch(err) {
//異步異常
console.log(err)
} finally {
console.log('done')
}
};
getApi().then(res => {
return res.json(); //async 返回的 promise 物件會在第一個 then 裡面調用
})
定義一個匿名自己執行的 async
函式
(async () => {
const res = await fetch('./post.json').then(res => res.json());
})();
//函數聲明
async function test() {
};
//函數表達式
const test = async function() {
};
//物件寫法
let obj = {
name: 'leo',
async test () {
}
};
obj.test();
//class 寫法
class TestComponent {
async test () {
}
};
const a = new Test();
a.test();
//箭頭函式
const test = async () => {
};
這一篇主要是整理 ES6 中處理非同步的方式,下一篇開始會整理 JSX 的使用方式。